<!-- FaceRegister.vue -->
<template>
  <div class="face-registration">
    <h1>人脸注册</h1>

    <!-- 用户 ID -->
    <div class="form-group">
      <input v-model="userId" type="text" placeholder="请输入用户ID" class="input"/>
    </div>

    <!-- 上传 / 拍照 二选一 -->
    <el-tabs v-model="activeTab" type="border-card" @tab-change="onTabChange">
      <el-tab-pane label="本地上传" name="upload">
        <div class="upload-area" @click="$refs.fileInput.click()">
          <div v-if="previewUrl" class="preview"><img :src="previewUrl" alt="人脸"/></div>
          <div v-else class="upload-placeholder">
            <i class="icon"></i>
            <p>点击上传人脸照片</p>
            <p class="tips">支持 JPG/PNG 格式</p>
          </div>
          <input ref="fileInput" type="file" accept="image/*" @change="handleFileChange" hidden/>
        </div>
      </el-tab-pane>

      <el-tab-pane label="摄像头拍照" name="camera">
        <div class="camera-box">
          <video ref="video" autoplay playsinline muted class="video"></video>
          <canvas ref="canvas" style="display: none"></canvas>
          <div class="camera-bar">
            <el-button type="primary" @click="openCamera" :disabled="cameraOpen">打开摄像头</el-button>
            <el-button type="success" @click="takePhoto" :disabled="!cameraOpen">拍照</el-button>
            <el-button @click="closeCamera" :disabled="!cameraOpen">关闭摄像头</el-button>
          </div>
          <div v-if="shotUrl" class="shot-preview">
            <img :src="shotUrl" alt="抓拍"/>
            <div class="shot-bar">
              <el-button size="small" @click="retake">重拍</el-button>
            </div>
          </div>
        </div>
      </el-tab-pane>
    </el-tabs>

    <!-- 提交 -->
    <el-button
        type="primary"
        class="btn-register"
        :loading="loading"
        :disabled="!userId || !file"
        @click="submit"
    >
      {{ loading ? '注册中...' : '立即注册' }}
    </el-button>
  </div>
</template>

<script setup>
import {ref} from 'vue'
import {ElMessage} from 'element-plus'
import {userPostFaceInfoPicP} from '@/api/user'

/* 基础数据 */
const userId = ref('')
const loading = ref(false)
const activeTab = ref('upload')

/* ---------- 上传 ---------- */
const file = ref(null)
const previewUrl = ref('')

function handleFileChange(e) {
  const raw = e.target.files?.[0]
  if (!raw) return
  revokeAllUrls()
  file.value = raw
  previewUrl.value = URL.createObjectURL(raw)
}

/* ---------- 摄像头 ---------- */
const video = ref(null)
const canvas = ref(null)
const cameraOpen = ref(false)
const shotUrl = ref('')
let streamIns = null

async function openCamera() {
  try {
    const s = await navigator.mediaDevices.getUserMedia({
      video: {width: 640, height: 480, facingMode: 'user'},
      audio: false
    })
    video.value.srcObject = s
    streamIns = s
    cameraOpen.value = true
  } catch (e) {
    ElMessage.error('无法打开摄像头：' + e.message)
  }
}

function closeCamera() {
  streamIns?.getTracks().forEach(t => t.stop())
  video.value.srcObject = null
  cameraOpen.value = false
}

function takePhoto() {
  const ctx = canvas.value.getContext('2d')
  canvas.value.width = video.value.videoWidth
  canvas.value.height = video.value.videoHeight
  ctx.drawImage(video.value, 0, 0)
  canvas.value.toBlob(blob => {
    revokeAllUrls()
    const f = new File([blob], `${userId.value || 'user'}.jpg`, {type: 'image/jpeg'})
    file.value = f
    shotUrl.value = URL.createObjectURL(blob)
  }, 'image/jpeg', 0.9)
}

function retake() {
  revokeAllUrls()
  shotUrl.value = ''
  file.value = null
}

/* ---------- Tab 切换清理 ---------- */
function onTabChange(tab) {
  revokeAllUrls()
  previewUrl.value = ''
  shotUrl.value = ''
  file.value = null
  if (tab === 'upload') closeCamera()
}

/* ---------- 清理 blob URL ---------- */
function revokeAllUrls() {
  if (previewUrl.value) URL.revokeObjectURL(previewUrl.value)
  if (shotUrl.value) URL.revokeObjectURL(shotUrl.value)
}

/* ---------- 提交 ---------- */
async function submit() {
  if (!userId.value.trim()) return ElMessage.warning('请先填写用户ID')
  if (!file.value) return ElMessage.warning('请先上传或拍照')
  loading.value = true
  try {
    // 👇 拦截器已弹成功提示，这里只处理失败/异常
    await userPostFaceInfoPicP(userId.value, file.value)
    reset() // 成功就重置表单
  } catch (e) {
    // 失败提示已被拦截器弹出，这里啥也不用干
  } finally {
    loading.value = false
  }
}

function reset() {
  userId.value = ''
  file.value = null
  previewUrl.value = ''
  shotUrl.value = ''
  activeTab.value = 'upload'
  closeCamera()
}
</script>

<style scoped lang="scss">
.face-registration {
  max-width: 600px;
  margin: 40px auto;
  padding: 20px;
}

h1 {
  text-align: center;
  margin-bottom: 20px;
}

.form-group {
  text-align: center;
  margin-bottom: 20px;

  .input {
    width: 80%;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 4px;
  }
}

.upload-area {
  height: 200px;
  border: 2px dashed #ccc;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;

  .preview img {
    max-width: 100%;
    max-height: 200px;
    object-fit: contain;
  }

  .upload-placeholder {
    text-align: center;
    color: #666;

    .icon {
      font-size: 48px;
    }

    .tips {
      font-size: 12px;
      color: #999;
    }
  }
}

.camera-box {
  text-align: center;

  .video {
    width: 100%;
    max-width: 640px;
    border: 1px solid #ddd;
    border-radius: 4px;
  }

  .camera-bar {
    margin-top: 10px;
  }

  .shot-preview {
    margin-top: 15px;

    img {
      max-width: 300px;
      border: 1px solid #ccc;
      border-radius: 4px;
    }

    .shot-bar {
      margin-top: 8px;
    }
  }
}

.btn-register {
  width: 100%;
  margin-top: 20px;
}
</style>